/* 
    WhaleSpotter
    Copyright (C) 2007  Bob Mottram
    fuzzgun@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace whalespotter
{
    public class util
    {
        /// <summary>
        /// if the given image has an uneven stride straighten it out
        /// </summary>
        /// <param name="img"></param>
        /// <param name="img_width"></param>
        /// <param name="img_height"></param>
        /// <param name="stride"></param>
        /// <returns></returns>
        public static Byte[] evenStride(Byte[] img, int img_width, int img_height, int stride)
        {
            Byte[] result=null;

            int evStride = img_width * 3;
            if (evStride == stride)
                result = img;
            else
            {
                int diff = evStride - stride;
                //stride += diff;
                result = new Byte[img_width * img_height * 3];
                for (int y = 0; y < img_height; y++)
                {
                    int n = y * stride;
                    for (int x = 0; x < img_width; x++)
                    {
                        int n2 = n + (x * 3);
                        int n3 = (y * evStride) + (x * 3);
                        if ((n2 + 3 < img.Length) && (n3 + 3 < img.Length) && (n3 > -1))
                        {
                            for (int col = 0; col < 3; col++)
                            {
                                result[n3 + col] = img[n2 + col];
                            }
                        }
                    }
                }
            }

            return (result);
        }

        public static Byte[] loadFromBitmap(String filename, int image_width, int image_height, int bytes_per_pixel)
        {
            Byte[] bmp = new Byte[image_width * image_height * bytes_per_pixel];

            if (File.Exists(filename))
            {
                FileStream fp = new FileStream(filename, FileMode.Open);
                BinaryReader binfile = new BinaryReader(fp);
                int n = 54;
                int n2 = 0;
                Byte[] data = new Byte[(image_width * image_height * bytes_per_pixel) + n];
                binfile.Read(data, 0, (image_width * image_height * bytes_per_pixel) + n);
                for (int y = 0; y < image_height; y++)
                {
                    for (int x = 0; x < image_width; x++)
                    {
                        n2 = (((image_height - 1 - y) * image_width) + x) * 3;
                        for (int c = 0; c < bytes_per_pixel; c++)
                        {
                            bmp[n2 + c] = data[n];
                            n++;
                        }
                    }
                }
                binfile.Close();
                fp.Close();
            }
            return (bmp);
        }


        public static Byte[] loadFromPGM(String filename, int image_width, int image_height, int bytes_per_pixel)
        {
            Byte[] bmp = new Byte[image_width * image_height * bytes_per_pixel];

            if (File.Exists(filename))
            {
                FileStream fp = new FileStream(filename, FileMode.Open);
                BinaryReader binfile = new BinaryReader(fp);
                int n = 96;
                int n2 = 0;
                Byte[] data = new Byte[(image_width * image_height) + n];
                binfile.Read(data, 0, (image_width * image_height) + n);
                for (int y = 0; y < image_height; y++)
                {
                    for (int x = 0; x < image_width; x++)
                    {
                        for (int c = 0; c < bytes_per_pixel; c++)
                        {
                            bmp[n2] = data[n];
                            n2++;
                        }
                        n++;
                    }
                }
                binfile.Close();
                fp.Close();
            }
            return (bmp);
        }


        //---------------------------------------------------------------------------------------------
        //draw a line between two points in the given image
        //---------------------------------------------------------------------------------------------
        public static void drawLine(Byte[] img, int img_width, int img_height,
                                    int x1, int y1, int x2, int y2, int r, int g, int b, int linewidth, bool overwrite)
        {
            int w, h, x, y, step_x, step_y, dx, dy, xx2, yy2;
            float m;

            dx = x2 - x1;
            dy = y2 - y1;
            w = Math.Abs(dx);
            h = Math.Abs(dy);
            if (x2 >= x1) step_x = 1; else step_x = -1;
            if (y2 >= y1) step_y = 1; else step_y = -1;

            if (w > h)
            {
                if (dx != 0)
                {
                    m = dy / (float)dx;
                    x = x1;
                    while (x != x2 + step_x)
                    {
                        y = (int)(m * (x - x1)) + y1;

                        for (xx2 = x - linewidth; xx2 <= x + linewidth; xx2++)
                            for (yy2 = y - linewidth; yy2 <= y + linewidth; yy2++)
                            {
                                if ((xx2 >= 0) && (xx2 < img_width) && (yy2 >= 0) && (yy2 < img_height))
                                {
                                    int n = ((img_width * yy2) + xx2) * 3;
                                    if ((img[n] == 0) || (!overwrite))
                                    {
                                        img[n] = (Byte)b;
                                        img[n + 1] = (Byte)g;
                                        img[n + 2] = (Byte)r;
                                    }
                                    else
                                    {
                                        img[n] = (Byte)((img[n] + b) / 2);
                                        img[n + 1] = (Byte)((img[n] + g) / 2);
                                        img[n + 2] = (Byte)((img[n] + r) / 2);
                                    }
                                }
                            }

                        x += step_x;
                    }
                }
            }
            else
            {
                if (dy != 0)
                {
                    m = dx / (float)dy;
                    y = y1;
                    while (y != y2 + step_y)
                    {
                        x = (int)(m * (y - y1)) + x1;
                        for (xx2 = x - linewidth; xx2 <= x + linewidth; xx2++)
                            for (yy2 = y - linewidth; yy2 <= y + linewidth; yy2++)
                            {
                                if ((xx2 >= 0) && (xx2 < img_width) && (yy2 >= 0) && (yy2 < img_height))
                                {
                                    int n = ((img_width * yy2) + xx2) * 3;
                                    if ((img[n] == 0) || (!overwrite))
                                    {
                                        img[n] = (Byte)b;
                                        img[n + 1] = (Byte)g;
                                        img[n + 2] = (Byte)r;
                                    }
                                    else
                                    {
                                        img[n] = (Byte)((img[n] + b) / 2);
                                        img[n + 1] = (Byte)((img[n] + g) / 2);
                                        img[n + 2] = (Byte)((img[n] + r) / 2);
                                    }
                                }
                            }

                        y += step_y;
                    }
                }
            }
        }

        /// <summary>
        /// returns true if the given value is a map coordinate
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool isMapCoordinate(String value)
        {
            value = value.ToUpper();
            if ((value.Contains("N")) || (value.Contains("S")) ||
                (value.Contains("E")) || (value.Contains("W")))
                return (true);
            else
                return (false);
        }

        /// <summary>
        /// turn a map coordinate, such as 20.4E, into a floating point value
        /// </summary>
        /// <param name="mapCoordinate"></param>
        /// <returns></returns>
        public static float MapToFloat(String mapCoordinate)
        {
            float coord = 0;
            mapCoordinate = mapCoordinate.ToUpper();

            if (mapCoordinate != "")
            {
                if (isMapCoordinate(mapCoordinate))
                {
                    String mapCoord = mapCoordinate.Substring(0, mapCoordinate.Length - 1);
                    coord = Convert.ToSingle(mapCoord);
                    if ((mapCoordinate.Contains("N")) || (mapCoordinate.Contains("W")))
                        coord = -coord;
                }
                else coord = Convert.ToSingle(mapCoordinate);
            }
            return (coord);
        }

        public static String FloatToMap(float coord, bool isLongitude)
        {
            String mapCoordinate = "";

            if (isLongitude)
            {
                if (coord > 0)
                    mapCoordinate = Convert.ToString(coord) + "E";
                else
                    mapCoordinate = Convert.ToString(-coord) + "W";
            }
            else
            {
                if (coord > 0)
                    mapCoordinate = Convert.ToString(coord) + "S";
                else
                    mapCoordinate = Convert.ToString(-coord) + "N";
            }
            return (mapCoordinate);
        }

    }
}
